#include "stdafx.h"

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

struct Address
{
public:
	int address;
	int accessed;
};
class DirectMap
{
private:
	int cacheSize; //size of the cache
	int numBlocks; //number of blocks in cache
	int blockSize; //size of the cache
	//int address; //address to cache
	int blockNum; //number of the block address goesin
	Address cache[1][1]; //holds the cache itself cache[index][set]
	int hit; //number of hits processed
	int miss; //number of misses processed
	string fileName;  //Holds file name
	int associativity;

	/*PROTOTYPES*/
	/*
	int Search(); //returns 1 if address is in cache (hit), 0 if not (miss)
	int ReadAddress(); //returns address as read from file
	void Mapping();	//Main method that handles the logic and calls other methods
	*/

public:
	DirectMap(string f, int size, int a, int b)
	{
		fileName = f;
		cacheSize = size;
		associativity = a;
		numBlocks = b;
		hit = 0;
		miss = 0;
		numBlocks = cacheSize / blockSize;
		cache[cacheSize][associativity];
	}
	void DirectMap::Mapping(int address)
	{
		//addresss = FileRead
		int modBlock; //which word of the block does it go in?
		blockNum = numBlocks % address;
		modBlock = blockSize % address;
		int temp;
		temp = Search(address, modBlock);
		if(temp == 1)
		{
			hit++; //increment num hits
		}
		else if(temp == 0)
		{
			miss++; //increment num misses
			int loc;
			loc = blockNum * blockSize + modBlock;
			int lru = 0;
			for(int i = 0; i < associativity; i++) //check for which set was LRU
			{
				if(cache[loc][i].accessed > lru)
				{
					lru = i;
				}
			}
			cache[loc][lru].address = address;
			int fill = loc +1; //get indexer to fill block
			int fAdd = address + 1;
			while (fill != loc) //until we wraparound full circle
			{
				if(fill == blockNum * blockSize + blockSize - 1) //if at end of block (ex: b = 4, bNum = 1; 1 * 4 + 4 - 1 = 7
				{
					fill = fill - blockSize + 1; //move to head of block; ex: 7 - 4 + 1 = 4
				}
				cache[fill][lru].address = fAdd; //add the address to location
				fAdd++; //increment address
				cache[fill][lru].accessed = 0; //reset accessed value
			}
		}
	}
	int DirectMap::Search(int address, int bLoc)//bLoc = modBlock
	{
		int ret = 0; //return value, inititalize assuming miss
		int searchTop; //holds the top of previous block. Search blockNum - 1 and blockNum
		searchTop = bLoc + blockSize;
		int searchBottom; //holds bottom of current block for where to stop looking
		searchBottom = blockNum * blockSize - 1;
		for(int i = searchTop; i <= searchBottom; i++)
		{
			for(int j = 0; j < associativity; j++)
			{
				if(cache[i][j].address == address) //if address exists
				{
					ret = 1;
					int blockFound; //block where found
					blockFound = (int)i / blockSize; //block found = the integer - division result.
					int resetTop; //start at top of block
					resetTop = blockFound * blockSize; //set to top of found block
					int resetBottom;
					resetBottom = resetTop + blockSize - 1; //set to bottom of block
					for(int k = resetTop; k <= resetBottom; k++)
					{
						cache[k][j].accessed = 0;
					}
				}
			}
		}
		return ret;
	}
	void DirectMap::Output()
	{
		for(int i = 0; i < cacheSize; i++)
		{
			for(int j = 0; j < associativity; j++)
			{
				cout << cache[i][j].address;
				cout << " ";
			}
			cout << "\n";
		}
		cout << "Misses: " + miss;
		cout << "Hits: " + hit;
	}
	void DirectMap::loadList()
	{
		string line;
		
		ifstream myfile (fileName);
		if (myfile.is_open())
		{
			while ( myfile.good())
			{
				getline (myfile,line);
				int address;
				istringstream(line) >> address;
				//TODO ACCOUNT FOR RELATIVITY IN ADDRESSES
				cout << line << endl;
			}
			myfile.close();
			Output();
		}
		else
		{
			cout << "Unable to open file";
		}		
	}
};